import numpy as np
import pygame
import physics
import math
from pygame.locals import *

class basicObject(physics.phy, pygame.sprite.Sprite):
    def __init__(self, pos, r = 10, color = (255, 0, 255), direc = 1, hv = 3, jv = 5, dt = 10,type = "object"):
        physics.phy.__init__(self)
        pygame.sprite.Sprite.__init__(self)

        self._type = type

        self._r = r
        self._color = color
        self.m = 10

        self._direc = direc
        self.__hv = hv
        self.__jv = jv

        self.__barrier = False  # horizon barrier tag
        self._groundtag = True  # on the ground tag

        self._update_time = 0
        self._dt = dt

        self.image = pygame.Surface([self._r, self._r])
        self.image.fill(self._color)
        self.rect = self.image.get_rect()
        self.rect.topleft = pos

    def update(self, current_time):
        if self._update_time < current_time:
            self.status_refresh(self._dt)
            self.rect.x, self.rect.y = self.rect.x + self._v[0], self.rect.y + self._v[1]
            self._update_time = current_time + self._dt

    def status_refresh(self, t):
        self.cacu_v(t)
        if self._groundtag:
            self.vertical_move_clean()
            if math.fabs(self._v[0]) > 0:
                 sign = self._v[0]/math.fabs(self._v[0])
                 self.add_f("f", (-sign * math.fabs(self._f["N"][1]) * self._u, 0))
                 if self._F[0] / self._f["f"][0] > 0:
                     if self._F[0] / self._v[0] < 0 and math.fabs(self._F[0] * t) > math.fabs(self._v[0]):
                        self.del_f("f")
                        self._v[0] = 0
            else:
                self.del_f("f")
        if self.__barrier:
            self.horizon_move_clean()

    def hori_move(self, direc):
        self._direc = direc
        self._v[0] = direc * self.__hv

    # jump action
    def jump(self):
        if self._groundtag:
            self._v[1] = -self.__jv
            self.off_ground()

    # ground tag
    def on_ground(self):
        self.add_f("N", (0, -self._f["G"][1]))
        self._groundtag = True
    def off_ground(self):
        self.del_f("N")
        self.del_f("f")
        self._groundtag = False

    def move_clean(self,direc):
        #0 -- horizon 1--vertical
        self._v[direc] = 0
        self._a[direc] = 0
        #for f in self.__F:
        #    f[direc] = 0    #a bug here

    def horizon_move_clean(self):
        self.move_clean(0)

    def vertical_move_clean(self):
        self.move_clean(1)

    def v_inverse(self):
        temp = self.__v[1]
        self._a[1] = 0
        self._v[1] = -temp

class Bullet(basicObject):

    def __init__(self, pos, r = 5, color = (0, 0, 255), iv = 0, angle = 0, g = 0.01, type = "stone"):
        basicObject.__init__(self, pos, r, color, type = type)
        self.off_ground()
        self.m = 1
        self.__angle = angle
        if type == "stone" or type == "grenade":
            self.set_g(g)
            self.add_f("G", (0, self.m * g))
            v = 5
        elif type == "gun" or type == "autogun":
            v = 10

        if iv != 0:
            v = iv
        self._v[0] = math.cos(self.__angle) * v
        self._v[1] = math.sin(self.__angle) * v
    def explode(self, objectGroup):
        if self._type == "grenade":
            pos = (self.rect.topleft[0], self.rect.topleft[1]-5)
            for i in range(0, 180, 10):
                piece = Bullet(pos, angle = -math.radians(i), iv =3, type = "stone")
                objectGroup.add(piece)

class Player(basicObject):
    def __init__(self, pos, r = 100, color = (255, 0, 255), direc = 1, hv = 3, jv = 5, type = "player0"):
        basicObject.__init__(self, pos, r, color, direc, hv, type = type)
        self.cd = 0
        self.change_cd = 0
        self.amor_change("stone")

    def emit_bullet(self):
        if self.cd == 0:
            self.cd = self.__cdTime
            return (self.rect.topleft, self._direc, self._amorType)
        else:
            return ()

    def amor_change(self, kind):
        self._amorType = kind
        if kind == "stone":
            self.__cdTime = 100
            self.__amorNumber = 1
        elif kind == "gun":
            self.__cdTime = 20
            self.__amorNumber = 2
        elif kind == "autogun":
            self.__cdTime = 10
            self.__amorNumber = 3
        elif kind == "grenade":
            self.__cdTime = 30
            self.__amorNumber = 4

    def rotate_amor(self):
        if self.change_cd != 0:
            return
        self.__amorNumber = (self.__amorNumber + 1) % 4
        if self.__amorNumber == 1:
            kind = "stone"
        elif self.__amorNumber == 2:
            kind = "gun"
        elif self.__amorNumber == 3:
            kind = "autogun"
        elif self.__amorNumber == 0:
            kind = "grenade"
        self.amor_change(kind)
        self.change_cd = 10
    def get_emit_direc(self,mouse_pos):
        return math.atan2(mouse_pos[1] - self.rect.topleft[1], mouse_pos[0] - self.rect.topleft[0])
    def update(self, current_time):
        if self._update_time < current_time:
            self.status_refresh(self._dt)
            self.rect.x, self.rect.y = self.rect.x + self._v[0], self.rect.y + self._v[1]
            self._update_time = current_time + self._dt
            self.cd -= 1
            self.change_cd -= 1
            if self.cd < 0:
                self.cd = 0
            if self.change_cd < 0:
                self.change_cd = 0